package com.yaohe.common.key;

import java.nio.ByteBuffer;

/**
 * The general behavior of a key that must be stored and compared. Key can be
 * stored in hashmap since the hashCode function has been overrided. Keys can be
 * compared based on the underlying byte array values.
 * 
 */
public class Key {
	/*
	 * Do not know the exact type of the key value(int, long, string etc.) So we
	 * use general byte arrays
	 */
	private byte[] bytes;
	
	protected boolean emptyKey;
	
	public Key() {
		this.emptyKey = true;
	}

	/**
	 * Constructor. A key can actually constructed from any kind of object that
	 * can be consistently converted to a byte array
	 * 
	 * @param value
	 */
	public Key(byte[] value) {
		if (value == null) {
			throw new IllegalArgumentException("value can not be null");
		}
		this.bytes = value;
		emptyKey = false;
	}

	public byte[] getBytes() {
		return bytes;
	}

	public void setBytes(byte[] b){
		this.bytes = b;
		this.emptyKey = false;
	}
	@Override
	/**
	 * Two keys are equal if and only if the byte arrays
	 * behind the keys have exactly the same value.
	 */
	public boolean equals(Object o) {
		if (!(o instanceof Key)) {
			return false;
		}
		return this.compareTo((Key) o) == 0;
	}

	@Override
	public int hashCode() {
		int result = 0;
		for (int i = 0; i < bytes.length; i++) {
			result ^= Byte.valueOf(bytes[i]).hashCode();
		}

		return result;
	}

	/**
	 * Compare two keys byte-wisely. Return 0 if and only if two keys are equal
	 * 
	 * @param other
	 * @return
	 */
	public int compareTo(Key other) {
		int result = this.bytes.length - other.getBytes().length;
		for (int i = 0; result == 0 && i < bytes.length; i++) {
			result = this.bytes[i] - other.bytes[i];
		}

		return result;
	}

	public int getIntValue() {

		byte[] bytes = this.getBytes();
		
		ByteBuffer b = ByteBuffer.wrap(bytes);

		return b.getInt();

	}

	public long getLongValue() {

		byte[] bytes = this.getBytes();
		
		ByteBuffer b = ByteBuffer.wrap(bytes);

		return b.getLong();

	}

	public String getStringValue() {

		byte[] bytes = this.getBytes();

		return new String(bytes);

	}
	
	public boolean isEmpty(){return emptyKey;}
}
